import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:m3u8d/src/ffmpeg/ffmpeg.dart';
import 'package:m3u8d/src/rust/api/m3u8.dart';
import 'package:m3u8d/src/rust/frb_generated.dart';
import 'package:permission_handler/permission_handler.dart';

Future<void> main() async {
  await RustLib.init();
  // await setupLogger();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      themeMode: ThemeMode.dark,
      theme: ThemeData(
        // This is the theme of your application.
        //
        // TRY THIS: Try running your application with "flutter run". You'll see
        // the application has a purple toolbar. Then, without quitting the app,
        // try changing the seedColor in the colorScheme below to Colors.green
        // and then invoke "hot reload" (save your changes or press the "hot
        // reload" button in a Flutter-supported IDE, or press "r" if you used
        // the command line to start the app).
        //
        // Notice that the counter didn't reset back to zero; the application
        // state is not lost during the reload. To reset the state, use hot
        // restart instead.
        //
        // This works for code too, not just values: Most code changes can be
        // tested with just a hot reload.
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        brightness: Brightness.light,
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        brightness: Brightness.dark,
      ),
      home: const MyHomePage(title: 'm3u8d'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String? savePath = Platform.isAndroid
      ? "/storage/emulated/0/Movies"
      : Platform.isLinux
          ? Platform.environment['HOME'] != null
              ? "${Platform.environment['HOME']}/Videos"
              : ""
          : "";
  String? m3u8Url = "";
  String? name = "";
  late TextEditingController _nameController;
  late TextEditingController _urlController;
  M3U8Task? m3u8task;
  double? _progress = 0.0;
  String? step;

  @override
  void initState() {
    super.initState();
    _nameController = TextEditingController(text: name);
    _urlController = TextEditingController(text: m3u8Url);
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    final perantWidth = MediaQuery.of(context).size.width;
    final paddWidth = perantWidth /
        (Platform.isAndroid
            ? 20
            : Platform.isLinux
                ? 5
                : 10);
    return Scaffold(
      appBar: AppBar(
        // TRY THIS: Try changing the color here to a specific color (to
        // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
        // change color while the other colors stay the same.
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
          child: Padding(
        padding: EdgeInsets.symmetric(horizontal: paddWidth),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(savePath ?? '未选择保存目录'),
            if (m3u8task != null)
              Row(
                children: [
                  SizedBox(
                    width: 5,
                  ),
                  if (step != null) Text(step!),
                  SizedBox(
                    width: 10,
                  ),
                  Expanded(
                    child: LinearProgressIndicator(
                      value: _progress,
                    ),
                  ),
                ],
              ),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 20),
              child: Column(
                children: [
                  TextField(
                    // autofocus: true,
                    controller: _urlController,
                    decoration: InputDecoration(
                      prefixIcon: const Icon(
                        Icons.link,
                        color: Colors.grey,
                      ),
                      // alignLabelWithHint: true,
                      helperStyle: const TextStyle(fontSize: 14),
                      hintText: "m3u8 url",
                      hintStyle: const TextStyle(
                        height: 2.0,
                      ),
                      enabledBorder: OutlineInputBorder(
                        /*边角*/
                        borderRadius: BorderRadius.circular(20),
                        borderSide: const BorderSide(
                          color: Colors.white, //边线颜色为白色
                          width: 1, //边线宽度为2
                        ),
                      ),
                      focusedBorder: OutlineInputBorder(
                        borderSide: const BorderSide(
                          color: Colors.green, //边框颜色为白色
                          width: 1, //宽度为5
                        ),
                        borderRadius: BorderRadius.circular(20),
                      ),
                    ),
                  ),
                  SizedBox(
                    height: 20,
                  ),
                  TextField(
                    // autofocus: true,
                    controller: _nameController,
                    decoration: InputDecoration(
                      prefixIcon: const Icon(
                        Icons.video_file,
                        color: Colors.grey,
                      ),
                      // alignLabelWithHint: true,
                      helperStyle: const TextStyle(fontSize: 14),
                      hintText: "保存名称",
                      hintStyle: const TextStyle(
                        height: 2.0,
                      ),
                      enabledBorder: OutlineInputBorder(
                        /*边角*/
                        borderRadius: BorderRadius.circular(20),
                        borderSide: const BorderSide(
                          color: Colors.white, //边线颜色为白色
                          width: 1, //边线宽度为2
                        ),
                      ),
                      focusedBorder: OutlineInputBorder(
                        borderSide: const BorderSide(
                          color: Colors.green, //边框颜色为白色
                          width: 1, //宽度为5
                        ),
                        borderRadius: BorderRadius.circular(20),
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                OutlinedButton(
                    child: Text("选择保存路径"),
                    onPressed: () async {
                      if (!await requestStoragePermission(request: true)) {
                        tip(context, "未授权");
                      }
                      String? selectedDirectory =
                          await FilePicker.platform.getDirectoryPath();
                      setState(() {
                        savePath = selectedDirectory;
                      });
                    }),
                OutlinedButton(
                    child: Text("清空"),
                    onPressed: () async {
                      setState(() {
                        _urlController.text = "";
                        _nameController.text = "";
                        if (m3u8task != null) {
                          deleteDir(m3u8task!.cacheDir);
                          m3u8task = null;
                        }

                        _progress = null;
                      });
                    })
              ],
            )
          ],
        ),
      )),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.play_arrow),
        onPressed: () async {
          m3u8Url = _urlController.text;
          name = _nameController.text;
          if (m3u8Url == null || m3u8Url == "") {
            tip(context, "url未输入");
          } else if (name == null || name == "") {
            tip(context, "名称未输入");
          } else if (savePath == null) {
            tip(context, "保存目录未选择");
          } else {
            if (!await requestStoragePermission(request: true)) {
              tip(context, "未授权");
              return;
            }

            setState(() {
              m3u8task = M3U8Task(
                  url: m3u8Url!,
                  workDir: savePath!,
                  name: name!,
                  work: BigInt.from(8));
              _progress = 0.0;
              step = "下载";
            });
            await m3u8task!.init();
            m3u8task!.download(
              callback: (p0) {
                setState(() {
                  _progress = p0;
                });
              },
            ).then(
              (value) async {
                setState(() {
                  step = "合并";
                  _progress = 0.1;
                });
                final outfile = '${m3u8task?.workDir}/${m3u8task?.name}.mp4';
                final out = await FFMPEG.inst.mergeM3u8(
                    m3u8Path: '${m3u8task?.m3U8Path}', outPath: outfile);
                setState(() {
                  _progress = 99.0;
                });

                if (out) {
                  tip(context, "下载完成: $outfile");
                  deleteDir(m3u8task!.cacheDir);
                } else {
                  tip(context, "下载失败");
                }
                setState(() {
                  m3u8task = null;
                  _progress = null;
                  step = null;
                });
              },
            );
          }
        },
      ),
    );
  }
}

void deleteDir(String path) async {
  Directory dir = Directory(path);
  if (await dir.exists()) {
    await dir.delete(recursive: true);
  }
}

void tip(BuildContext context, String text) {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      content: Text(
        text,
        textAlign: TextAlign.center,
        style: const TextStyle(
          fontSize: 45,
          fontWeight: FontWeight.bold,
        ),
      ),
    ),
  );
}

/// Granting Storage Permission.
/// Requesting Granular media permissions for Android 13 (API 33) doesnt work for some reason.
/// Currently the target API is set to 32.
/// [request] will prompt dialog if not granted.
Future<bool> requestStoragePermission({bool request = true}) async {
  var granted = false;
  if (!Platform.isAndroid) {
    return true;
  }
  if (await Permission.manageExternalStorage.isPermanentlyDenied) {
    if (request) {
      // -- user denied, should open settings.
      await openAppSettings();
    }
  } else if (await Permission.manageExternalStorage.isDenied) {
    if (request) {
      final st = await Permission.manageExternalStorage.request();
      if (st.isPermanentlyDenied) {
        await openAppSettings();
      }
      granted = st.isGranted;
    }
  } else {
    granted = true;
  }
  return granted;
}
